using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation;

using EntLibContrib.Validation.Configuration;

namespace EntLibContrib.Validation.Validators
{
    [ConfigurationElementType(typeof(CompositeRulesetValidatorData))]
    public class CompositeRulesetValidator : Validator
    {
        public static string[] GetTargetRulesets(string targetRulesets)
        {
            if (targetRulesets == null)
            {
                return new string[0];
            }
            else
            {
                List<string> items = new List<string>();

                foreach (string targetRuleset in targetRulesets.Split(','))
                {
                    items.Add(targetRuleset.Trim());
                }

                return items.ToArray();
            }
        }

        private Type targetType;
        private ValidationSpecificationSource source;
        private string[] targetRulesets;
        private IConfigurationSource configurationSource;
        private string configurationSourceName;

        public CompositeRulesetValidator(Type targetType, string[] targetRulesets)
            : this(targetType, targetRulesets, ValidationSpecificationSource.Both)
        {
        }

        public CompositeRulesetValidator(Type targetType, string[] targetRulesets, ValidationSpecificationSource source, IConfigurationSource configurationSource)
            : this(targetType, targetRulesets, source)
        {
            this.configurationSource = configurationSource;
        }

        public CompositeRulesetValidator(Type targetType, string[] targetRulesets, ValidationSpecificationSource source, string configurationSourceName)
            : this(targetType, targetRulesets, source)
        {
            this.configurationSourceName = configurationSourceName;
        }

        public CompositeRulesetValidator(Type targetType, string[] targetRulesets, ValidationSpecificationSource source)
            : base(null, null)
        {
            ArgumentValidation.Validate("targetType", targetType, DefaultValidators.NotNullValidator);
            ArgumentValidation.Validate("targetRulesets", targetRulesets, DefaultValidators.NotNullValidator);
            ArgumentValidation.Validate("source", source, DefaultValidators.EnumDefinedValidator);

            this.targetType = targetType;
            this.targetRulesets = targetRulesets;
            this.source = source;
        }

        protected override string DefaultMessageTemplate
        {
            get { return null; }
        }

        protected override void DoValidate(object objectToValidate, object currentTarget, string key, ValidationResults validationResults)
        {
            foreach (string targetRuleset in targetRulesets)
            {
                Validator validator = null;

                switch (source)
                {
                    case ValidationSpecificationSource.Attributes:
                        validator = ValidationFactory.CreateValidatorFromAttributes(targetType, targetRuleset);
                        break;

                    case ValidationSpecificationSource.Configuration:
                        validator = ValidationFactory.CreateValidatorFromConfiguration(targetType, targetRuleset, SafeConfigurationSource);
                        break;

                    default:
                        validator = ValidationFactory.CreateValidator(targetType, targetRuleset, SafeConfigurationSource);
                        break;
                }

                validator.Validate(objectToValidate, validationResults);
            }
        }

        protected virtual IConfigurationSource SafeConfigurationSource
        {
            get
            {
                if (configurationSource == null)
                {
                    if (string.IsNullOrEmpty(configurationSourceName))
                    {
                        configurationSource = ConfigurationSourceFactory.Create();
                    }
                    else
                    {
                        configurationSource = ConfigurationSourceFactory.Create(configurationSourceName);
                    }
                }
                 
                return configurationSource;
            }
        }
    }
}
